﻿#region License

// Copyright (c) 2008, BXO Solutions AB
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice, 
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright 
//       notice, this list of conditions and the following disclaimer in the 
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the BXO Solutions AB nor the names of its 
//       contributors may be used to endorse or promote products derived from 
//       this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#endregion

using System;
using System.Linq;
using Bxo.TestingPortal.Entities;
using Bxo.TestingPortal.WebApplication.Controllers;
using Castle.MonoRail.Framework;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using Rhino.Commons;
using Rhino.Commons.ForTesting;

namespace Bxo.TestingPortal.WebApplication.Tests {
    [TestFixture]
    public class CategoryControllerFixture : InProjectControllerTest {
        #region Setup/Teardown

        [SetUp]
        public void SetUp() {
            UnitOfWork.Start();
            DatabaseTestFixtureBase.CurrentContext.SetupDatabase(UnitOfWork.CurrentSession);

            this.testee = new CategoryController();
        }

        [TearDown]
        public void TearDown() {
            UnitOfWork.Current.Dispose();
        }

        #endregion

        [TestFixtureSetUp]
        public void TestFixtureSetUp() {
            DatabaseTestFixtureBase.IntializeNHibernateAndIoC(PersistenceFramework.ActiveRecord,
                                                              "Windsor.boo",
                                                              DatabaseEngine.SQLite,
                                                              MappingInfo.FromAssemblyContaining<Project>());
        }

        private CategoryController testee;

        private void AssertThatCategoryIsSet(Category category) {
            Assert.That(this.Testee.PropertyBag["category"], Is.SameAs(category), "Problem with the category passed to the view.");
        }

        protected override Controller Testee {
            get { return this.testee; }
        }

        [Test]
        public void Add_RendersViewCorrectly() {
            this.PrepareController(this.testee, "Category", "Add");

            int projectId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                Repository<Project>.Save(project);
                projectId = project.Id;
            }

            this.testee.Add(Repository<Project>.Get(projectId));

            Project actual = Repository<Project>.Get(projectId);

            // View.
            this.AssertThatProjectIsSet(actual);
            this.AssertThatViewIsSelected("Add");
        }

        [Test]
        public void AddCommit_AddsNewCategory() {
            this.PrepareController(this.testee, "Category", "AddCommit");

            int projectId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                Repository<Project>.Save(project);
                projectId = project.Id;
            }

            this.testee.AddCommit(Repository<Project>.Get(projectId), "cat_name");

            Project actual = Repository<Project>.Get(projectId);

            Assert.That(actual.Categories.Count(), Is.EqualTo(1), "Category has not been added.");
            Category category = actual.Categories.ElementAt(0);
            Assert.That(category, Is.Not.Null, "Added category is null.");
            Assert.That(category.Project, Is.SameAs(actual), "Problem with category project.");
            Assert.That(category.Name, Is.EqualTo("cat_name"), "Problem with category name.");
            Assert.That(category.Scenarios, Is.Empty, "Problem with category scenarios.");

            // View.
            this.AssertThatCategoryIsSet(category);
            this.AssertThatProjectIsSet(actual);
            this.AssertThatViewIsSelected("AddCommit");
        }

        [Test]
        public void Delete_RendersCorrectView() {
            this.PrepareController(this.testee, "Category", "Delete");

            int projectId;
            int categoryId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                var category = new Category("the_category");
                project.Categories.Add(category);
                Repository<Project>.Save(project);
                projectId = project.Id;
                categoryId = category.Id;
            }

            this.testee.Delete(Repository<Category>.Get(categoryId));

            // View.
            this.AssertThatCategoryIsSet(Repository<Category>.Get(categoryId));
            this.AssertThatProjectIsSet(Repository<Project>.Get(projectId));
            this.AssertThatViewIsSelected("Delete");
        }

        [Test]
        public void DeleteCommit_DeletesCategory() {
            this.PrepareController(this.testee, "Category", "DeleteCommit");

            int projectId;
            int categoryId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                var category = new Category("the_category");
                project.Categories.Add(category);
                var scenario = new Scenario(new ScenarioVersion("some_scenario", String.Empty));
                project.Scenarios.Add(scenario);
                category.Scenarios.Add(scenario);
                Repository<Project>.Save(project);
                projectId = project.Id;
                categoryId = category.Id;
            }

            this.testee.DeleteCommit(Repository<Category>.Get(categoryId));

            Project actualProject = Repository<Project>.Get(projectId);
            Assert.That(actualProject.Categories, Has.No.Member(Repository<Category>.Get(categoryId)), "Category has not been deleted.");

            // View.
            this.AssertThatProjectIsSet(actualProject);
            this.AssertThatViewIsSelected("DeleteCommit");
        }

        [Test]
        public void Edit_RendersCorrectView() {
            this.PrepareController(this.testee, "category", "edit");

            int categoryId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                var category = new Category("a_category");
                project.Categories.Add(category);
                Repository<Project>.Save(project);
                categoryId = category.Id;
            }

            this.testee.Edit(Repository<Category>.Get(categoryId));

            Category actualCategory = Repository<Category>.Get(categoryId);

            // Form.
            Assert.That(this.testee.PropertyBag["name"], Is.SameAs(actualCategory.Name));

            // View.
            this.AssertThatCategoryIsSet(actualCategory);
            this.AssertThatProjectIsSet(actualCategory.Project);
            this.AssertThatViewIsSelected("Edit");
        }

        [Test]
        public void EditCommit_ChangesCategoryProperties() {
            this.PrepareController(this.testee, "category", "editcommit");

            int categoryId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                var category = new Category("a_category");
                project.Categories.Add(category);
                Repository<Project>.Save(project);
                categoryId = category.Id;
            }

            this.testee.EditCommit(Repository<Category>.Get(categoryId), "a_new_category_name");

            Category actualCategory = Repository<Category>.Get(categoryId);

            Assert.That(actualCategory.Name, Is.EqualTo("a_new_category_name"));

            // View.
            this.AssertThatCategoryIsSet(actualCategory);
            this.AssertThatProjectIsSet(actualCategory.Project);
            this.AssertThatViewIsSelected("EditCommit");
        }

        [Test]
        public void List_ReturnsAllCategories() {
            this.PrepareController(this.testee, "category", "list");

            int projectId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                var category1 = new Category("cat1");
                var category2 = new Category("cat2");
                project.Categories.Add(category1);
                project.Categories.Add(category2);
                Repository<Project>.Save(project);
                projectId = project.Id;
            }

            this.testee.List(Repository<Project>.Get(projectId));

            // View.
            Assert.That(this.testee.PropertyBag["categories"], Is.EquivalentTo(Repository<Category>.FindAll().ToList()));
            this.AssertThatProjectIsSet(Repository<Project>.Get(projectId));
            this.AssertThatViewIsSelected("List");
        }

        [Test]
        public void Show_RendersViewCorrectly() {
            this.PrepareController(this.testee, "category", "show");

            int categoryId;

            using (new DataPreparationScope()) {
                var project = new Project("a_project");
                var category = new Category("the_category");
                project.Categories.Add(category);
                Repository<Project>.Save(project);
                categoryId = category.Id;
            }

            this.testee.Show(Repository<Category>.Get(categoryId));

            Category actualCategory = Repository<Category>.Get(categoryId);

            this.AssertThatCategoryIsSet(actualCategory);
            this.AssertThatProjectIsSet(actualCategory.Project);
            this.AssertThatViewIsSelected("Show");
        }
    }
}